Passed
Push — master ( b62cea...5105f1 )
by EMP
01:14
created

main.js ➔ getMsgId   A

Complexity

Conditions 4

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 14
rs 9.85
c 0
b 0
f 0
cc 4
1
"use strict";
2
3
sodium.ready.then(function() {
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
4
5
const ae = new AllEars(function(ok) {
1 ignored issue
show
Bug introduced by
The variable AllEars seems to be never declared. If this is a global, consider adding a /** global: AllEars */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6
	if (ok) {
7
		const greeting = localStorage.greeting;
1 ignored issue
show
Bug introduced by
The variable localStorage seems to be never declared. If this is a global, consider adding a /** global: localStorage */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
8
		if (greeting) {
9
			document.getElementById("greeting").textContent = greeting;
10
			document.getElementById("txt_pg").value = greeting;
11
		}
12
13
		document.getElementById("txt_skey").style.background = "#466";
14
		document.getElementById("txt_skey").maxLength = "64";
15
	} else {
16
		console.log("Failed to load All-Ears");
17
	}
18
});
19
20
function TabState(cur, max, btnDele, btnUpdt) {
21
	this.cur = cur;
22
	this.max = max;
23
	this.btnDele = btnDele;
24
	this.btnUpdt = btnUpdt;
25
}
26
27
const tabs = [
28
	new TabState(0, 0, false, true), // Inbox
29
	new TabState(0, 0, false, true), // Outbx
30
	new TabState(0, 2, true, false), // Write
31
	new TabState(0, 2, false, false), // Notes
32
	new TabState(0, 3, false, true) // Tools
33
];
34
35
let showHeaders = false;
36
37
let tab = 0;
38
const TAB_INBOX = 0;
39
const TAB_DRBOX = 1;
40
const TAB_WRITE = 2;
41
const TAB_NOTES = 3;
42
const TAB_TOOLS = 4;
43
44
// Helper functions
45
function getCountryName(countryCode) {
46
	switch (countryCode) {
47
		case "DZ": return "Algeria";
48
		case "AO": return "Angola";
49
		case "BJ": return "Benin";
50
		case "BW": return "Botswana";
51
		case "BF": return "Burkina Faso";
52
		case "BI": return "Burundi";
53
		case "CV": return "Cabo Verde";
54
		case "CM": return "Cameroon";
55
		case "CF": return "Central African Republic";
56
		case "TD": return "Chad";
57
		case "KM": return "Comoros";
58
		case "CD": return "Congo";
59
		case "DJ": return "Djibouti";
60
		case "EG": return "Egypt";
61
		case "GQ": return "Equatorial Guinea";
62
		case "ER": return "Eritrea";
63
		case "SZ": return "Eswatini";
64
		case "ET": return "Ethiopia";
65
		case "GA": return "Gabon";
66
		case "GM": return "Gambia";
67
		case "GH": return "Ghana";
68
		case "GW": return "Guinea-Bissau";
69
		case "GN": return "Guinea";
70
		case "CI": return "Ivory Coast";
71
		case "KE": return "Kenya";
72
		case "LS": return "Lesotho";
73
		case "LR": return "Liberia";
74
		case "LY": return "Libya";
75
		case "MG": return "Madagascar";
76
		case "MW": return "Malawi";
77
		case "ML": return "Mali";
78
		case "MR": return "Mauritania";
79
		case "MU": return "Mauritius";
80
		case "YT": return "Mayotte";
81
		case "MA": return "Morocco";
82
		case "MZ": return "Mozambique";
83
		case "NA": return "Namibia";
84
		case "NE": return "Niger";
85
		case "NG": return "Nigeria";
86
		case "CG": return "Republic of the Congo";
87
		case "RW": return "Rwanda";
88
		case "RE": return "Réunion";
89
		case "SH": return "Saint Helena";
90
		case "SN": return "Senegal";
91
		case "SC": return "Seychelles";
92
		case "SL": return "Sierra Leone";
93
		case "SO": return "Somalia";
94
		case "ZA": return "South Africa";
95
		case "SS": return "South Sudan";
96
		case "SD": return "Sudan";
97
		case "ST": return "São Tomé and Príncipe";
98
		case "TZ": return "Tanzania";
99
		case "TG": return "Togo";
100
		case "TN": return "Tunisia";
101
		case "UG": return "Uganda";
102
		case "EH": return "Western Sahara";
103
		case "ZM": return "Zambia";
104
		case "ZW": return "Zimbabwe";
105
		case "AQ": return "Antarctica";
106
		case "BV": return "Bouvet Island";
107
		case "TF": return "French Southern Territories";
108
		case "HM": return "Heard Island and McDonald Islands";
109
		case "GS": return "South Georgia and the South Sandwich Islands";
110
		case "AF": return "Afghanistan";
111
		case "AM": return "Armenia";
112
		case "AZ": return "Azerbaijan";
113
		case "BH": return "Bahrain";
114
		case "BD": return "Bangladesh";
115
		case "BT": return "Bhutan";
116
		case "IO": return "British Indian Ocean Territory";
117
		case "BN": return "Brunei";
118
		case "KH": return "Cambodia";
119
		case "CN": return "China";
120
		case "CC": return "Cocos [Keeling] Islands";
121
		case "GE": return "Georgia";
122
		case "JO": return "Hashemite Kingdom of Jordan";
123
		case "HK": return "Hong Kong";
124
		case "IN": return "India";
125
		case "ID": return "Indonesia";
126
		case "IR": return "Iran";
127
		case "IQ": return "Iraq";
128
		case "IL": return "Israel";
129
		case "JP": return "Japan";
130
		case "KZ": return "Kazakhstan";
131
		case "KW": return "Kuwait";
132
		case "KG": return "Kyrgyzstan";
133
		case "LA": return "Laos";
134
		case "LB": return "Lebanon";
135
		case "MO": return "Macao";
136
		case "MY": return "Malaysia";
137
		case "MV": return "Maldives";
138
		case "MN": return "Mongolia";
139
		case "MM": return "Myanmar";
140
		case "NP": return "Nepal";
141
		case "KP": return "North Korea";
142
		case "OM": return "Oman";
143
		case "PK": return "Pakistan";
144
		case "PS": return "Palestine";
145
		case "PH": return "Philippines";
146
		case "QA": return "Qatar";
147
		case "SA": return "Saudi Arabia";
148
		case "SG": return "Singapore";
149
		case "KR": return "South Korea";
150
		case "LK": return "Sri Lanka";
151
		case "SY": return "Syria";
152
		case "TW": return "Taiwan";
153
		case "TJ": return "Tajikistan";
154
		case "TH": return "Thailand";
155
		case "TR": return "Turkey";
156
		case "TM": return "Turkmenistan";
157
		case "AE": return "United Arab Emirates";
158
		case "UZ": return "Uzbekistan";
159
		case "VN": return "Vietnam";
160
		case "YE": return "Yemen";
161
		case "AL": return "Albania";
162
		case "AD": return "Andorra";
163
		case "AT": return "Austria";
164
		case "BY": return "Belarus";
165
		case "BE": return "Belgium";
166
		case "BA": return "Bosnia and Herzegovina";
167
		case "BG": return "Bulgaria";
168
		case "HR": return "Croatia";
169
		case "CY": return "Cyprus";
170
		case "CZ": return "Czechia";
171
		case "DK": return "Denmark";
172
		case "EE": return "Estonia";
173
		case "FO": return "Faroe Islands";
174
		case "FI": return "Finland";
175
		case "FR": return "France";
176
		case "DE": return "Germany";
177
		case "GI": return "Gibraltar";
178
		case "GR": return "Greece";
179
		case "GG": return "Guernsey";
180
		case "HU": return "Hungary";
181
		case "IS": return "Iceland";
182
		case "IE": return "Ireland";
183
		case "IM": return "Isle of Man";
184
		case "IT": return "Italy";
185
		case "JE": return "Jersey";
186
		case "XK": return "Kosovo";
187
		case "LV": return "Latvia";
188
		case "LI": return "Liechtenstein";
189
		case "LU": return "Luxembourg";
190
		case "MT": return "Malta";
191
		case "MC": return "Monaco";
192
		case "ME": return "Montenegro";
193
		case "NL": return "Netherlands";
194
		case "MK": return "North Macedonia";
195
		case "NO": return "Norway";
196
		case "PL": return "Poland";
197
		case "PT": return "Portugal";
198
		case "LT": return "Republic of Lithuania";
199
		case "MD": return "Republic of Moldova";
200
		case "RO": return "Romania";
201
		case "RU": return "Russia";
202
		case "SM": return "San Marino";
203
		case "RS": return "Serbia";
204
		case "SK": return "Slovakia";
205
		case "SI": return "Slovenia";
206
		case "ES": return "Spain";
207
		case "SJ": return "Svalbard and Jan Mayen";
208
		case "SE": return "Sweden";
209
		case "CH": return "Switzerland";
210
		case "UA": return "Ukraine";
211
		case "GB": return "United Kingdom";
212
		case "VA": return "Vatican City";
213
		case "AX": return "Åland";
214
		case "AI": return "Anguilla";
215
		case "AG": return "Antigua and Barbuda";
216
		case "AW": return "Aruba";
217
		case "BS": return "Bahamas";
218
		case "BB": return "Barbados";
219
		case "BZ": return "Belize";
220
		case "BM": return "Bermuda";
221
		case "BQ": return "Bonaire, Sint Eustatius, and Saba";
222
		case "VG": return "British Virgin Islands";
223
		case "CA": return "Canada";
224
		case "KY": return "Cayman Islands";
225
		case "CR": return "Costa Rica";
226
		case "CU": return "Cuba";
227
		case "CW": return "Curaçao";
228
		case "DM": return "Dominica";
229
		case "DO": return "Dominican Republic";
230
		case "SV": return "El Salvador";
231
		case "GL": return "Greenland";
232
		case "GD": return "Grenada";
233
		case "GP": return "Guadeloupe";
234
		case "GT": return "Guatemala";
235
		case "HT": return "Haiti";
236
		case "HN": return "Honduras";
237
		case "JM": return "Jamaica";
238
		case "MQ": return "Martinique";
239
		case "MX": return "Mexico";
240
		case "MS": return "Montserrat";
241
		case "NI": return "Nicaragua";
242
		case "PA": return "Panama";
243
		case "PR": return "Puerto Rico";
244
		case "BL": return "Saint Barthélemy";
245
		case "LC": return "Saint Lucia";
246
		case "MF": return "Saint Martin";
247
		case "PM": return "Saint Pierre and Miquelon";
248
		case "VC": return "Saint Vincent and the Grenadines";
249
		case "SX": return "Sint Maarten";
250
		case "KN": return "St Kitts and Nevis";
251
		case "TT": return "Trinidad and Tobago";
252
		case "TC": return "Turks and Caicos Islands";
253
		case "VI": return "U.S. Virgin Islands";
254
		case "US": return "United States";
255
		case "AS": return "American Samoa";
256
		case "AU": return "Australia";
257
		case "CX": return "Christmas Island";
258
		case "CK": return "Cook Islands";
259
		case "TL": return "Democratic Republic of Timor-Leste";
260
		case "FM": return "Federated States of Micronesia";
261
		case "FJ": return "Fiji";
262
		case "PF": return "French Polynesia";
263
		case "GU": return "Guam";
264
		case "KI": return "Kiribati";
265
		case "MH": return "Marshall Islands";
266
		case "NR": return "Nauru";
267
		case "NC": return "New Caledonia";
268
		case "NZ": return "New Zealand";
269
		case "NU": return "Niue";
270
		case "NF": return "Norfolk Island";
271
		case "MP": return "Northern Mariana Islands";
272
		case "PW": return "Palau";
273
		case "PG": return "Papua New Guinea";
274
		case "PN": return "Pitcairn Islands";
275
		case "WS": return "Samoa";
276
		case "SB": return "Solomon Islands";
277
		case "TK": return "Tokelau";
278
		case "TO": return "Tonga";
279
		case "TV": return "Tuvalu";
280
		case "UM": return "U.S. Minor Outlying Islands";
281
		case "VU": return "Vanuatu";
282
		case "WF": return "Wallis and Futuna";
283
		case "AR": return "Argentina";
284
		case "BO": return "Bolivia";
285
		case "BR": return "Brazil";
286
		case "CL": return "Chile";
287
		case "CO": return "Colombia";
288
		case "EC": return "Ecuador";
289
		case "FK": return "Falkland Islands";
290
		case "GF": return "French Guiana";
291
		case "GY": return "Guyana";
292
		case "PY": return "Paraguay";
293
		case "PE": return "Peru";
294
		case "SR": return "Suriname";
295
		case "UY": return "Uruguay";
296
		case "VE": return "Venezuela";
297
	}
0 ignored issues
show
Comprehensibility introduced by
There is no default case in this switch, so nothing gets returned when all cases fail. You might want to consider adding a default or return undefined explicitly.
Loading history...
298
}
299
300
function getCountryFlag(countryCode) {
301
	return sodium.to_string(new Uint8Array([
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
302
		240, 159, 135, 166 + countryCode.codePointAt(0) - 65,
303
		240, 159, 135, 166 + countryCode.codePointAt(1) - 65
304
	]));
305
}
306
307
function getClockIcon(d) {
308
	const h24 = d.getUTCHours();
309
	let h12 = (h24 === 0 ? 12 : ((h24 > 12) ? h24 - 12 : h24));
310
311
	const m60 = (d.getUTCMinutes() * 60) + d.getUTCSeconds();
312
	let m30 = 0;
313
	if (m60 <= 900) { // <= 15: round down to this hour
314
		m30 = 0;
315
	} else if (m60 > 900 && m60 < 2700) { // 15..45: round to half-past this hour
316
		m30 = 12;
317
	} else { // >= 45: round up to next hour
318
		h12++;
319
		m30 = 0;
320
	}
321
322
	return "&#" + ((128335 + h12) + m30) + ";";
323
}
324
325
function getMsgId(num) {
326
	let i;
327
	if (ae.GetExtMsgHeaders(num).toLowerCase().slice(0, 11) === "message-id:") {
328
		i = 0;
329
	} else {
330
		i = ae.GetExtMsgHeaders(num).toLowerCase().indexOf("\nmessage-id:");
331
		if (i < 1) return "ERR";
332
		i++;
333
	}
334
335
	const x = ae.GetExtMsgHeaders(num).slice(i + 11).trim();
336
	if (x[0] !== "<") return "ERR2";
337
	return x.slice(1, x.indexOf(">"));
338
}
339
340
function clearDisplay() {
341
	let el = document.getElementById("midright").getElementsByTagName("img");
342
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("audio");
343
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("video");
344
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("embed");
345
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("iframe");
346
	if (el.length !== 1) return;
347
348
	URL.revokeObjectURL(el[0].src);
1 ignored issue
show
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
349
	el[0].remove();
350
}
351
352
function displayFile(num) {
353
	const fileType = ae.GetUplMsgType(num);
354
355
	if (!fileType) { // Download
356
		const a = document.createElement("a");
357
		a.href = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
2 ignored issues
show
Bug introduced by
The variable Blob seems to be never declared. If this is a global, consider adding a /** global: Blob */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
358
		a.download = ae.GetUplMsgTitle(num);
359
		a.click();
360
361
		URL.revokeObjectURL(a.href);
362
		a.href = "";
363
		a.download = "";
364
		return;
365
	}
366
367
	clearDisplay();
368
369
	document.getElementById("midright").scroll(0, 0);
370
	document.getElementById("midright").setAttribute("data-msgid", ae.GetUplMsgIdHex(num));
371
	document.getElementById("btn_reply").disabled = true;
372
	document.getElementById("btn_mdele").disabled = false;
373
	document.getElementById("midright").children[0].hidden = true;
374
	document.getElementById("midright").children[1].textContent = ae.GetUplMsgTitle(num);
375
376
	switch (fileType) {
377
		case "text": {
378
			document.getElementById("midright").children[2].hidden = false;
379
			document.getElementById("midright").children[2].textContent = sodium.to_string(ae.GetUplMsgBody(num));
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
380
		break;}
381
382
		case "image": {
383
			document.getElementById("midright").children[2].hidden = true;
384
			const img = document.createElement("img");
385
			img.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
386
			document.getElementById("midright").appendChild(img);
387
388
			img.onclick = function() {
389
				if (!document.fullscreen)
390
					img.requestFullscreen();
391
				else
392
					document.exitFullscreen();
393
			};
394
		break;}
395
396
		case "audio": {
397
			document.getElementById("midright").children[2].hidden = true;
398
			const el = document.createElement("audio");
399
			el.controls = "controls";
400
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
401
			document.getElementById("midright").appendChild(el);
402
		break;}
403
404
		case "video": {
405
			document.getElementById("midright").children[2].hidden = true;
406
			const el = document.createElement("video");
407
			el.controls = "controls";
408
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
409
			document.getElementById("midright").appendChild(el);
410
		break;}
411
412
		case "pdf": {
413
			document.getElementById("midright").children[2].hidden = true;
414
			const el = document.createElement("embed");
415
			el.type = "application/pdf";
416
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer], {type: "application/pdf"}));
417
			document.getElementById("midright").appendChild(el);
418
		break;}
419
420
		case "html": {
421
			document.getElementById("midright").children[2].hidden = true;
422
			const el = document.createElement("iframe");
423
			el.allow = "";
424
			el.sandbox = "";
425
			el.csp = "base-uri 'none'; child-src 'none'; connect-src 'none'; default-src 'none'; font-src 'none'; form-action 'none'; frame-ancestors 'none'; frame-src 'none'; img-src 'none'; manifest-src 'none'; media-src 'none'; object-src 'none'; script-src 'none'; style-src 'none'; worker-src 'none';";
426
			el.srcdoc = sodium.to_string(ae.GetUplMsgBody(num).buffer);
427
			document.getElementById("midright").appendChild(el);
428
		break;}
429
	}
430
}
431
432
function displayMsg(isInt, num) {
433
	clearDisplay();
434
435
	document.getElementById("btn_mdele").disabled = false;
436
	document.getElementById("midright").scroll(0, 0);
437
	document.getElementById("midright").setAttribute("data-msgid", isInt? ae.GetIntMsgIdHex(num) : ae.GetExtMsgIdHex(num));
438
439
	const ts = isInt? ae.GetIntMsgTime(num) : ae.GetExtMsgTime(num);
440
441
	document.getElementById("btn_reply").disabled = false;
442
	document.getElementById("btn_reply").onclick = function() {
443
		document.getElementById("write_recv").value = isInt? ae.GetIntMsgFrom(num) : ae.GetExtMsgReplyAddress(num);
444
		document.getElementById("write_subj").value = isInt? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num);
445
		if (!document.getElementById("write_subj").value.startsWith("Re:")) document.getElementById("write_subj").value = "Re: " + document.getElementById("write_subj").value;
446
		document.querySelector("#write2_pkey > input").value = isInt? ae.GetIntMsgFromPk(num) : "";
447
448
		document.getElementById("write_recv").readOnly = !isInt;
449
		document.getElementById("write_subj").readOnly = !isInt;
450
		document.getElementById("write_subj").setAttribute("data-replyid", isInt? "" : getMsgId(num));
451
452
		tabs[TAB_WRITE].cur = 0;
453
		document.getElementById("btn_write").disabled = false;
454
		document.getElementById("btn_write").click();
455
		document.getElementById("write_body").focus();
456
457
		for (const opt of document.getElementById("write_from").options) {
458
			if (opt.value === (isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num))) {
459
				opt.selected = true;
460
			}
461
		}
462
	};
463
464
	document.getElementById("midright").children[0].hidden = false;
465
	document.getElementById("midright").children[2].hidden = false;
466
467
	if (isInt) {
468
		document.getElementById("midright").children[1].textContent = ae.GetIntMsgTitle(num);
469
		document.getElementById("midright").children[2].textContent = ae.GetIntMsgBody(num);
470
	} else {
471
		document.getElementById("midright").children[2].innerHTML = "";
472
473
		const headers = document.createElement("p");
474
		headers.textContent = ae.GetExtMsgHeaders(num);
475
		headers.className = "mono";
476
		headers.hidden = !showHeaders;
477
		document.getElementById("midright").children[2].appendChild(headers);
478
479
		const body = document.createElement("p");
480
		body.textContent = ae.GetExtMsgBody(num);
481
		document.getElementById("midright").children[2].appendChild(body);
482
483
		document.getElementById("midright").children[1].textContent = ae.GetExtMsgTitle(num);
484
		document.getElementById("midright").children[1].onclick = function() {showHeaders = !showHeaders; headers.hidden = !showHeaders;};
485
		document.getElementById("midright").children[1].style.cursor = "pointer";
486
	}
487
488
	document.getElementById("readmsg_envto").textContent = isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num);
489
490
	const tzOs = new Date().getTimezoneOffset();
491
	const tz = ((tzOs < 0) ? "+" : "-") + Math.floor(tzOs / -60).toString().padStart(2, "0") + (tzOs % 60 * -1).toString().padStart(2, "0");
492
	const msgDate = new Date((ts * 1000) + (tzOs * -60000));
493
494
	document.getElementById("readmsg_date").children[0].innerHTML = getClockIcon(msgDate);
495
	document.getElementById("readmsg_date").children[1].textContent = msgDate.toISOString().slice(0, 19).replace("T", " ") + " " + tz;
496
497
	if (!isInt) {
498
		document.getElementById("readmsg_ip").hidden = false;
499
		document.getElementById("readmsg_country").hidden = false;
500
		document.getElementById("readmsg_tls").hidden = false;
501
		document.getElementById("readmsg_greet").hidden = false;
502
503
		const cc = ae.GetExtMsgCountry(num);
504
505
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetExtMsgIp(num);
506
		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
507
		document.getElementById("readmsg_tls").children[0].textContent = ae.GetExtMsgTLS(num);
508
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetExtMsgGreet(num);
509
		document.getElementById("readmsg_envfrom").textContent = ae.GetExtMsgFrom(num);
510
511
		let flagText = "";
512
		if (!ae.GetExtMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
513
		if (!ae.GetExtMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
514
		if (!ae.GetExtMsgFlagPExt(num)) flagText += "<abbr title=\"The sender did not use the Extended (ESMTP) protocol\">SMTP</abbr> ";
515
		if (!ae.GetExtMsgFlagQuit(num)) flagText += "<abbr title=\"The sender did not issue the required QUIT command\">QUIT</abbr> ";
516
		if (ae.GetExtMsgFlagRare(num)) flagText += "<abbr title=\"The sender issued unusual command(s)\">RARE</abbr> ";
517
		if (ae.GetExtMsgFlagFail(num)) flagText += "<abbr title=\"The sender issued invalid command(s)\">FAIL</abbr> ";
518
		if (ae.GetExtMsgFlagPErr(num)) flagText += "<abbr title=\"The sender violated the protocol\">PROT</abbr> ";
519
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
520
	} else {
521
		document.getElementById("readmsg_ip").hidden = true;
522
		document.getElementById("readmsg_country").hidden = true;
523
		document.getElementById("readmsg_greet").hidden = true;
524
525
		document.getElementById("readmsg_tls").hidden = false;
526
		document.getElementById("readmsg_tls").children[0].textContent = ae.GetIntMsgFromPk(num);
527
528
		let symbol = "<span title=\"Invalid level\">&#x26a0;</span>";
529
		if (ae.GetIntMsgFrom(num) === "system") {if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"System\">&#x1f162;</span>";} // S (System)
530
		else if (ae.GetIntMsgLevel(num) === 0) symbol = "<span title=\"Level 0 User\">&#x1f10c;</span>"; // 0
531
		else if (ae.GetIntMsgLevel(num) === 1) symbol = "<span title=\"Level 1 User\">&#x278a;</span>"; // 1
532
		else if (ae.GetIntMsgLevel(num) === 2) symbol = "<span title=\"Level 2 User\">&#x278b;</span>"; // 2
533
		else if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"Administrator\">&#x1f150;</span>"; // A (Admin)
534
		document.getElementById("readmsg_envfrom").innerHTML = symbol + " " + ae.GetIntMsgFrom(num);
535
536
		let flagText = "";
537
		if (!ae.GetIntMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
538
		if (!ae.GetIntMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
539
		if (ae.GetIntMsgFlagE2ee(num)) flagText += "<abbr title=\"End-to-end encrypted\">E2EE</abbr> ";
540
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
541
	}
542
}
543
544
// Interface
545
function addMsg(isInt, i) {
546
	const row = document.getElementById("tbl_inbox").insertRow(-1);
547
	row.setAttribute("data-msgid", isInt? ae.GetIntMsgIdHex(i) : ae.GetExtMsgIdHex(i));
548
549
	const cellTime = row.insertCell(-1);
550
	const ts = isInt? ae.GetIntMsgTime(i) : ae.GetExtMsgTime(i);
551
	cellTime.setAttribute("data-ts", ts);
552
	cellTime.textContent = new Date((ts * 1000) + (new Date().getTimezoneOffset() * -60000)).toISOString().slice(0, 10);
553
554
	const cellSubj = row.insertCell(-1);
555
	cellSubj.textContent = isInt? ae.GetIntMsgTitle(i) : ae.GetExtMsgTitle(i);
556
557
	if (isInt) {
558
		const cellSnd = row.insertCell(-1);
559
		cellSnd.textContent = ae.GetIntMsgFrom(i);
560
		cellSnd.className = (ae.GetIntMsgFrom(i).length === 16) ? "mono" : "";
561
	} else {
562
		const from1 = ae.GetExtMsgFrom(i);
563
		const from2 = from1.substring(from1.indexOf("@") + 1);
564
		const cc = ae.GetExtMsgCountry(i);
565
		const cellSnd1 = row.insertCell(-1);
566
		cellSnd1.textContent = from1.substring(0, from1.indexOf("@"));
567
568
		const flag = document.createElement("abbr");
569
		flag.textContent = getCountryFlag(cc);
570
		flag.title = getCountryName(cc);
571
572
		const fromText = document.createElement("span");
573
		fromText.textContent = " " + from2;
574
575
		const cellSnd2 = row.insertCell(-1);
576
		cellSnd2.appendChild(flag);
577
		cellSnd2.appendChild(fromText);
578
	}
579
580
	row.onclick = function() {
581
		displayMsg(isInt, i);
582
	};
583
}
584
585
function getRowsPerPage() {
586
	const tbl = document.getElementById("tbl_inbox");
587
	tbl.innerHTML = "";
588
	const row = tbl.insertRow(-1);
589
	const cell = row.insertCell(-1);
590
	cell.textContent = "0";
591
592
	const rowsPerPage = Math.floor(getComputedStyle(document.getElementById("div_inbox")).height.replace("px", "") / getComputedStyle(document.querySelector("#tbl_inbox > tbody > tr:first-child")).height.replace("px", "")) - 1; // -1 allows space for 'load more'
593
	tbl.innerHTML = "";
594
	return rowsPerPage;
595
}
596
597
function addMessages() {
598
	const rowsPerPage = getRowsPerPage();
599
	let skipMsgs = rowsPerPage * tabs[TAB_INBOX].cur;
600
601
	const maxExt = ae.GetExtMsgCount();
602
	const maxInt = ae.GetIntMsgCount();
603
604
	tabs[TAB_INBOX].max = Math.floor((maxExt + maxInt - 1) / rowsPerPage);
605
606
	let numExt = 0;
607
	let numInt = 0;
608
	let numAdd = 0;
609
610
	while (numAdd < rowsPerPage) {
611
		const tsInt = (numInt < maxInt) ? ae.GetIntMsgTime(numInt) : -1;
612
		const tsExt = (numExt < maxExt) ? ae.GetExtMsgTime(numExt) : -1;
613
		if (tsInt === -1 && tsExt === -1) break;
614
615
		if (tsInt !== -1 && (tsExt === -1 || tsInt > tsExt)) {
616
			if (skipMsgs > 0) skipMsgs--; else {addMsg(true, numInt); numAdd++;}
617
			numInt++;
618
		} else if (tsExt !== -1) {
619
			if (skipMsgs > 0) skipMsgs--; else {addMsg(false, numExt); numAdd++;}
620
			numExt++;
621
		}
622
	}
623
624
	if (ae.GetReadyMsgBytes() < ae.GetTotalMsgBytes()) {
625
		const inbox = document.getElementById("tbl_inbox");
626
		const row = inbox.insertRow(-1);
627
		const cell = row.insertCell(-1);
628
		cell.textContent = "Load more (" + Math.round((ae.GetTotalMsgBytes() - ae.GetReadyMsgBytes()) / 1024) + " KiB left)";
629
630
		row.onclick = function() {
631
			this.onclick = "";
632
633
			ae.Message_Browse(false, false, function(successBrowse) {
634
				document.getElementById("tbl_inbox").style.opacity = 1;
635
636
				if (successBrowse) {
637
					addMessages();
638
					addUploads();
639
					addSent();
640
					if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
641
				}
642
			});
643
		};
644
	}
645
}
646
647
function addUploads() {
648
	const tbl = document.getElementById("tbd_uploads");
649
	tbl.innerHTML = "";
650
651
	for (let i = 0; i < ae.GetUplMsgCount(); i++) {
652
		const row = tbl.insertRow(-1);
653
		row.setAttribute("data-msgid", ae.GetUplMsgIdHex(i));
654
655
		let cell;
656
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetUplMsgTime(i) * 1000).toISOString().slice(0, 10);
657
658
		cell = row.insertCell(-1); cell.textContent = ae.GetUplMsgTitle(i);
659
		cell.onclick = function() {displayFile(this.parentElement.rowIndex - 1);};
660
661
		cell = row.insertCell(-1); cell.textContent = (ae.GetUplMsgBytes(i) / 1024).toFixed(1);
662
663
		cell = row.insertCell(-1);
664
		if (ae.GetUplMsgIdHex(i)) {
665
			cell.innerHTML = "<button data-msgid=\"" + ae.GetUplMsgIdHex(i) + "\" type=\"button\">X</button>";
666
667
			cell.children[0].onclick = function() {
668
				const tr = this.parentElement.parentElement;
669
				ae.Message_Delete(this.getAttribute("data-msgid"), function(success) {
670
					if (success) tr.remove();
671
				});
672
			};
673
		}
674
	}
675
}
676
677
function displayOutMsg(num) {
678
	clearDisplay();
679
	document.getElementById("midright").scroll(0, 0);
680
	document.getElementById("midright").setAttribute("data-msgid", ae.GetOutMsgIdHex(num));
681
	document.getElementById("btn_reply").disabled = true;
682
	document.getElementById("btn_mdele").disabled = false;
683
	document.getElementById("midright").children[0].hidden = false;
684
	document.getElementById("midright").children[2].hidden = false;
685
686
	document.getElementById("midright").children[1].textContent = ae.GetOutMsgSubj(num);
687
	document.getElementById("midright").children[2].textContent = ae.GetOutMsgBody(num);
688
689
	document.getElementById("readmsg_envto").textContent = ae.GetOutMsgTo(num);
690
	document.getElementById("readmsg_envfrom").textContent = ae.GetOutMsgFrom(num);
691
	document.getElementById("readmsg_to").textContent = ae.GetOutMsgMxDom(num);
692
693
	const ts = ae.GetOutMsgTime(num);
694
	const tzOs = new Date().getTimezoneOffset();
695
	const tz = ((tzOs < 0) ? "+" : "-") + Math.floor(tzOs / -60).toString().padStart(2, "0") + (tzOs % 60 * -1).toString().padStart(2, "0");
696
	document.getElementById("readmsg_date").children[1].textContent = new Date((ts * 1000) + (tzOs * -60000)).toISOString().slice(0, 19).replace("T", " ") + " " + tz;
697
698
	const isInt = ae.GetOutMsgIsInt(num);
699
	document.getElementById("readmsg_ip").hidden      = isInt;
700
	document.getElementById("readmsg_country").hidden = isInt;
701
	document.getElementById("readmsg_tls").hidden     = isInt;
702
	document.getElementById("readmsg_greet").hidden   = isInt;
703
704
	if (!isInt) {
705
//		const cc = ae.GetExtMsgCountry(num);
706
707
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetOutMsgIp(num);
708
//		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
709
//		document.getElementById("readmsg_tls").children[0].textContent = ae.GetOutMsgTLS(num);
710
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetOutMsgGreet(num);
711
	}
712
713
	let flagText = "";
714
	if (!ae.GetOutMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
715
	if (!ae.GetOutMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
716
	if (ae.GetOutMsgFlagE2ee(num)) flagText += "<abbr title=\"End-to-end encrypted\">E2EE</abbr> ";
717
	document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
718
}
719
720
function addSent() {
721
	const tbl = document.getElementById("tbl_drbox");
722
	tbl.innerHTML = "";
723
724
	for (let i = 0; i < ae.GetOutMsgCount(); i++) {
725
		const row = tbl.insertRow(-1);
726
		row.setAttribute("data-msgid", ae.GetOutMsgIdHex(i));
727
728
		let cell;
729
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetOutMsgTime(i) * 1000).toISOString().slice(0, 10);
730
		cell = row.insertCell(-1); cell.textContent = ae.GetOutMsgSubj(i);
731
		row.onclick = function() {displayOutMsg(i);};
732
	}
733
}
734
735
function updateAddressCounts() {
736
	document.getElementById("limit_normal").textContent = (ae.GetAddressCountNormal() + "/" + ae.GetLimitNormalA(ae.GetUserLevel())).padStart(ae.GetLimitNormalA(ae.GetUserLevel()) > 9 ? 5 : 1);
737
	document.getElementById("limit_shield").textContent = (ae.GetAddressCountShield() + "/" + ae.GetLimitShieldA(ae.GetUserLevel())).padStart(ae.GetLimitShieldA(ae.GetUserLevel()) > 9 ? 5 : 1);
738
	document.getElementById("limit_total").textContent = ((ae.GetAddressCountNormal() + ae.GetAddressCountShield()) + "/" + ae.GetAddrPerUser()).padStart(5);
739
740
	const limitReached = (ae.GetAddressCountNormal() + ae.GetAddressCountShield() >= 31);
741
	document.getElementById("btn_address_create_normal").disabled = (limitReached || ae.GetAddressCountNormal() >= ae.GetLimitNormalA(ae.GetUserLevel()));
742
	document.getElementById("btn_address_create_shield").disabled = (limitReached || ae.GetAddressCountShield() >= ae.GetLimitShieldA(ae.GetUserLevel()));
743
}
744
745
function adjustLevel(pubkey, level, c) {
746
	const fs = document.getElementById("fs_accs");
747
	fs.disabled = true;
748
749
	ae.Account_Update(pubkey, level, function(success) {
750
		fs.disabled = false;
751
752
		if (success) {
753
			c[4].textContent = level;
754
			c[5].children[0].disabled = (level === 3);
755
			c[6].children[0].disabled = (level === 0);
756
		}
757
	});
758
}
759
760
function addAccountToTable(i) {
761
	const tblAccs = document.getElementById("tbd_accs");
762
	const row = tblAccs.insertRow(-1);
763
	let cell;
764
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserPkHex(i);
765
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSpace(i);
766
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserNAddr(i);
767
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSAddr(i);
768
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserLevel(i);
769
770
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">+</button>";
771
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent, 10) + 1, c);};
772
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 3);
773
774
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">&minus;</button>";
775
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent, 10) - 1, c);};
776
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 0);
777
778
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">X</button>";
779
	cell.children[0].onclick = function() {
780
		const tr = this.parentElement.parentElement;
781
		ae.Account_Delete(tr.cells[0].textContent, function(success) {
782
			if (success) tr.remove();
783
		});
784
	};
785
}
786
787
function reloadAccount() {
788
	// Limits
789
	const tblLimits = document.getElementById("tbl_limits");
790
	if (ae.IsUserAdmin()) {
791
		for (let i = 0; i < 4; i++) {
792
			tblLimits.rows[i].cells[1].children[0].disabled = false;
793
			tblLimits.rows[i].cells[2].children[0].disabled = false;
794
			tblLimits.rows[i].cells[3].children[0].disabled = false;
795
796
			tblLimits.rows[i].cells[1].children[0].value = ae.GetLimitStorage(i) + 1;
797
			tblLimits.rows[i].cells[2].children[0].value = ae.GetLimitNormalA(i);
798
			tblLimits.rows[i].cells[3].children[0].value = ae.GetLimitShieldA(i);
799
		}
800
	} else {
801
		const lvl = ae.GetUserLevel();
802
		tblLimits.rows[lvl].cells[1].children[0].value = ae.GetLimitStorage(lvl) + 1;
803
		tblLimits.rows[lvl].cells[2].children[0].value = ae.GetLimitNormalA(lvl);
804
		tblLimits.rows[lvl].cells[3].children[0].value = ae.GetLimitShieldA(lvl);
805
	}
806
807
	// Accounts
808
	const tblAccs = document.getElementById("tbd_accs");
809
810
	// All: Our account
811
	const row = tblAccs.insertRow(-1);
812
	let cell;
813
	cell = row.insertCell(-1); cell.textContent = ae.GetUserPkHex();
814
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
815
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountNormal();
816
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountShield();
817
	cell = row.insertCell(-1); cell.textContent = ae.GetUserLevel();
818
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\" disabled=\"disabled\">+</button>";
819
820
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_downme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">&minus;</button>";
821
	cell.children[0].onclick = function() {
822
		const newLevel = parseInt(row.cells[4].textContent, 10) - 1;
823
		ae.Account_Update(ae.GetUserPkHex(), newLevel, function(success) {
824
			if (success) row.cells[4].textContent = newLevel;
825
		});
826
	};
827
828
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_killme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">X</button>";
829
	cell.children[0].onclick = function() {
830
		ae.Account_Delete(ae.GetUserPkHex(), function(success) {
831
			if (success) row.remove();
832
		});
833
	};
834
835
	document.getElementById("txt_reg").disabled = !ae.IsUserAdmin();
836
	document.getElementById("btn_reg").disabled = !ae.IsUserAdmin();
837
838
	// Contacts
839
	for (let i = 0; i < ae.GetContactCount(); i++) {
840
		addContact(
841
			ae.GetContactMail(i),
842
			ae.GetContactName(i),
843
			ae.GetContactNote(i)
844
		);
845
	}
846
847
	// Addresses
848
	for (let i = 0; i < ae.GetAddressCount(); i++) {
849
		addAddress(i);
850
	}
851
852
	updateAddressCounts();
853
	addMessages();
854
	addUploads();
855
	addSent();
856
857
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
858
}
859
860
function deleteAddress(addr) {
861
	let btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
862
	for (let i = 0; i < btns.length; i++) btns[i].disabled = true;
863
864
	let addressToDelete = -1;
865
866
	for (let i = 0; i < ae.GetAddressCount(); i++) {
867
		if (addr === ae.GetAddress(i)) {
868
			addressToDelete = i;
869
			break;
870
		}
871
	}
872
873
	if (addressToDelete === -1) return;
874
875
	ae.Address_Delete(addressToDelete, function(success) {
876
		if (success) {
877
			document.getElementById("tbl_addrs").deleteRow(addressToDelete);
878
			document.getElementById("write_from").remove(addressToDelete);
879
			updateAddressCounts();
880
881
			const limitReached = (ae.GetAddressCountNormal() + ae.GetAddressCountShield() >= 31);
882
			document.getElementById("btn_address_create_normal").disabled = (limitReached || ae.GetAddressCountNormal() > ae.GetLimitNormalA(ae.GetUserLevel()));
883
			document.getElementById("btn_address_create_shield").disabled = (limitReached || ae.GetAddressCountShield() > ae.GetLimitShieldA(ae.GetUserLevel()));
884
885
			ae.Private_Update(function(success2) {
886
				if (!success2) console.log("Failed to update the Private field");
887
888
				btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
889
				for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
890
			});
891
		} else {
892
			console.log("Failed to delete address");
893
894
			btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
895
			for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
896
		}
897
	});
898
}
899
900 View Code Duplication
function shieldMix(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
901
	let newAddr = "";
902
903
	for (let i = 0; i < 16; i++) {
904
		switch (addr.charAt(i)) {
905
			case '1':
906
				newAddr += "1iIlL".charAt(Math.floor(Math.random() * 5));
907
				break;
908
			case '0':
909
				newAddr += "0oO".charAt(Math.floor(Math.random() * 3));
910
				break;
911
			case 'w':
912
				newAddr += "VvWw".charAt(Math.floor(Math.random() * 4));
913
				break;
914
			default:
915
				newAddr += (Math.random() > 0.5) ? addr.charAt(i) : addr.charAt(i).toUpperCase();
916
		}
917
	}
918
919
	return newAddr;
920
}
921
922
function addAddress(num) {
923
	const addrTable = document.getElementById("tbl_addrs");
924
	const row = addrTable.insertRow(-1);
925
	const cellAddr = row.insertCell(-1);
926
	const cellChk1 = row.insertCell(-1);
927
	const cellChk2 = row.insertCell(-1);
928
	const cellBtnD = row.insertCell(-1);
929
930
	cellAddr.textContent = ae.GetAddress(num);
931
	cellAddr.onclick = function() {
932
		if (cellAddr.textContent.length === 16)
933
			navigator.clipboard.writeText(shieldMix(cellAddr.textContent) + "@" + ae.GetDomainEml());
1 ignored issue
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
934
		else
935
			navigator.clipboard.writeText(cellAddr.textContent + "@" + ae.GetDomainEml());
936
	};
937
938
	cellChk1.innerHTML = ae.GetAddressAccExt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
939
	cellChk2.innerHTML = ae.GetAddressAccInt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
940
941
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
942
	cellBtnD.onclick = function() {deleteAddress(cellAddr.textContent);};
943
944
	const opt = document.createElement("option");
945
	opt.value = cellAddr.textContent;
946
	opt.textContent = cellAddr.textContent + "@" + ae.GetDomainEml();
947
	document.getElementById("write_from").appendChild(opt);
948
}
949
950
document.getElementById("btn_dele").onclick = function() {
951
	this.blur();
952
953
	if (tab === TAB_WRITE) {
954
		tabs[tab].cur = 0;
955
		updateTab();
956
957
		document.getElementById("write_recv").value = "";
958
		document.getElementById("write_subj").value = "";
959
		document.getElementById("write_body").value = "";
960
961
		document.getElementById("write_recv").readOnly = false;
962
		document.getElementById("write_subj").readOnly = false;
963
		document.getElementById("write_subj").setAttribute("data-replyid", "");
964
965
		document.getElementById("write_recv").focus();
966
	}
967
};
968
969
document.getElementById("btn_updt").onclick = function() {
970
	const btn = this;
971
	btn.disabled = true;
972
	btn.blur();
973
974
	if (tab === TAB_INBOX) {
975
		document.getElementById("tbl_inbox").style.opacity = 0.5;
976
977
		ae.Message_Browse(true, false, function(successBrowse) {
978
			document.getElementById("tbl_inbox").style.opacity = 1;
979
980
			if (successBrowse) {
981
				addMessages();
982
				addUploads();
983
				btn.disabled = false;
984
			} else {
985
				console.log("Failed to refresh");
986
				btn.disabled = false;
987
			}
988
		});
989
	}
990
};
991
992
document.getElementById("btn_mdele").onclick = function() {
993
	const btn = this;
994
	btn.blur();
995
	btn.disabled = true;
996
997
	const delId = document.getElementById("midright").getAttribute("data-msgid");
998
	if (!delId) return;
999
1000
	ae.Message_Delete(delId, function(success) {
1001
		if (success) {
1002
			["tbl_inbox", "tbl_drbox", "tbd_uploads"].forEach(function(tbl_name) {
1003
				const tbl = document.getElementById(tbl_name);
1004
				for (let i = 0; i < tbl.rows.length; i++) {if (tbl.rows[i].getAttribute("data-msgid") === delId) tbl.deleteRow(i);}
1005
			});
1006
1007
			addMessages();
1008
			addUploads();
1009
			addSent();
1010
		} else btn.disabled = false;
1011
	});
1012
};
1013
1014
function addContact(mail, name, note) {
1015
	const tbl = document.getElementById("tbl_ctact");
1016
	const row = tbl.insertRow(-1);
1017
	const cellMail = row.insertCell(-1);
1018
	const cellName = row.insertCell(-1);
1019
	const cellNote = row.insertCell(-1);
1020
	const cellBtnD = row.insertCell(-1);
1021
1022
	cellMail.textContent = mail;
1023
	cellName.textContent = name;
1024
	cellNote.textContent = note;
1025
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
1026
1027
	cellMail.contentEditable = true;
1028
	cellName.contentEditable = true;
1029
	cellNote.contentEditable = true;
1030
1031
	cellBtnD.onclick = function() {row.remove();};
1032
}
1033
1034
document.getElementById("btn_newcontact").onclick = function() {
1035
	addContact("", "", "");
1036
};
1037
1038
document.getElementById("btn_savecontacts").onclick = function() {
1039
	while (ae.GetContactCount() > 0) {
1040
		ae.DeleteContact(0);
1041
	}
1042
1043
	for (const row of document.getElementById("tbl_ctact").rows) {
1044
		ae.AddContact(row.cells[0].textContent, row.cells[1].textContent, row.cells[2].textContent);
1045
	}
1046
1047
	const btn = this;
1048
	btn.disabled = true;
1049
1050
	ae.Private_Update(function(success) {
1051
		btn.disabled = false;
1052
1053
		if (!success) {
1054
			console.log("Failed contacts update");
1055
		}
1056
	});
1057
};
1058
1059
function writeVerify() {
1060
	if (
1061
	   !document.getElementById("write_recv").reportValidity()
1062
	|| !document.getElementById("write_subj").reportValidity()
1063
	|| !document.getElementById("write_body").reportValidity()
1064
	) {tabs[TAB_WRITE].cur = 0; return;}
1065
1066
	document.getElementById("div_write_1").hidden = true;
1067
	document.getElementById("div_write_2").hidden = false;
1068
1069
	document.getElementById("write2_recv").textContent = document.getElementById("write_recv").value;
1070
	document.getElementById("write2_subj").textContent = document.getElementById("write_subj").value;
1071
	document.getElementById("write2_rply").textContent = document.getElementById("write_subj").getAttribute("data-replyid");
1072
	document.getElementById("write2_body").textContent = document.getElementById("write_body").value;
1073
1074
	if (document.getElementById("write_recv").value.indexOf("@") >= 0) {
1075
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value + "@" + ae.GetDomainEml();
1076
		document.getElementById("write2_pkey").hidden = true;
1077
	} else {
1078
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value;
1079
		document.getElementById("write2_pkey").hidden = false;
1080
	}
1081
}
1082
1083
function updateTab() {
1084
	switch (tab) {
1085
		case TAB_INBOX:
1086
			addMessages();
1087
		break;
1088
1089
		case TAB_DRBOX:
1090
			addSent();
1091
		break;
1092
1093
		case TAB_WRITE:
1094
			switch (tabs[tab].cur) {
1095
				case 0: // Write
1096
					document.getElementById("div_write_1").hidden = false;
1097
					document.getElementById("div_write_2").hidden = true;
1098
					document.getElementById("write_body").focus();
1099
				break;
1100
1101
				case 1: // Verify
1102
					writeVerify();
1103
				break;
1104
1105
				case 2: // Send
1106
					ae.Message_Create(
1107
						document.getElementById("write_subj").value,
1108
						document.getElementById("write_body").value,
1109
						document.getElementById("write_from").value,
1110
						document.getElementById("write_recv").value,
1111
						document.getElementById("write_subj").getAttribute("data-replyid"),
1112
						(document.getElementById("write2_recv").textContent.indexOf("@") > 0) ? null : sodium.from_base64(document.querySelector("#write2_pkey > input").value, sodium.base64_variants.ORIGINAL_NO_PADDING),
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1113
						function(success) {
1114
							if (success) {
1115
								console.log("Sent ok");
1116
							} else {
1117
								console.log("Failed sending");
1118
							}
1119
						}
1120
					);
1121
				break;
1122
			}
1123
		break;
1124
1125
		case TAB_NOTES:
1126
			for (let i = 0; i <= tabs[tab].max; i++) {
1127
				document.getElementById("div_notes").children[i].hidden = (i !== tabs[tab].cur);
1128
			}
1129
		break;
1130
1131
		case TAB_TOOLS:
1132
			for (let i = 0; i <= tabs[tab].max; i++) {
1133
				document.getElementById("div_tools").children[i].hidden = (i !== tabs[tab].cur);
1134
			}
1135
		break;
1136
	}
1137
1138
	document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
1139
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1140
}
1141
1142
document.getElementById("btn_left").onclick = function() {
1143
	tabs[tab].cur--;
1144
	if (tabs[tab].cur === 0) this.disabled = true;
1145
	if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
1146
	updateTab();
1147
	this.blur();
1148
};
1149
1150
document.getElementById("btn_rght").onclick = function() {
1151
	tabs[tab].cur++;
1152
	if (tabs[tab].cur === tabs[tab].max) this.disabled = true;
1153
	document.getElementById("btn_left").disabled = false;
1154
	updateTab();
1155
	this.blur();
1156
};
1157
1158
const buttons = document.querySelector("#main1 > .top").getElementsByTagName("button");
1159
for (let i = 0; i < buttons.length; i++) {
1160
	buttons[i].onclick = function() {
1161
		tab = i;
1162
1163
		for (let j = 0; j < buttons.length; j++) {
1164
			document.querySelector("#main1 > .mid").children[j].hidden = (tab !== j);
1165
			buttons[j].disabled = (tab === j);
1166
		}
1167
1168
		document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
0 ignored issues
show
Bug introduced by
The variable tab is changed as part of the for loop for example by i on line 1161. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
1169
		document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1170
		document.getElementById("btn_dele").disabled = !tabs[tab].btnDele;
1171
		document.getElementById("btn_updt").disabled = !tabs[tab].btnUpdt;
1172
1173
		updateTab();
1174
	};
1175
}
1176
1177
function addressCreate(addr) {
1178
	document.getElementById("btn_address_create_normal").disabled = true;
1179
	document.getElementById("btn_address_create_shield").disabled = true;
1180
1181
	ae.Address_Create(addr, function(success1) {
1182
		if (success1) {
1183
			ae.Private_Update(function(success2) {
1184
				updateAddressCounts();
1185
1186
				if (success2) {
1187
					addAddress(ae.GetAddressCount() - 1);
1188
					if (addr !== "SHIELD") document.getElementById("txt_address_create_normal").value = "";
1189
				} else {
1190
					console.log("Failed to update the Private field");
1191
				}
1192
			});
1193
		} else {
1194
			console.log("Failed to add address");
1195
			updateAddressCounts();
1196
		}
1197
	});
1198
}
1199
1200
document.getElementById("btn_address_create_normal").onclick = function() {
1201
	if (ae.GetAddressCountNormal() >= ae.GetLimitNormalA(ae.GetUserLevel()) || ae.GetAddressCountNormal() + ae.GetAddressCountShield() >= 31) return;
1202
1203
	const txtNewAddr = document.getElementById("txt_address_create_normal");
1204
	if (!txtNewAddr.reportValidity()) return;
1205
1206
	addressCreate(txtNewAddr.value);
1207
};
1208
1209
document.getElementById("btn_address_create_shield").onclick = function() {
1210
	if (ae.GetAddressCountShield() >= ae.GetLimitShieldA(ae.GetUserLevel()) || ae.GetAddressCountNormal() + ae.GetAddressCountShield() >= 31) return;
1211
1212
	addressCreate("SHIELD");
1213
};
1214
1215
document.getElementById("btn_address_update").onclick = function() {
1216
	const btn = this;
1217
	btn.disabled = true;
1218
1219
	const rows = document.getElementById("tbl_addrs").rows;
1220
1221
	for (let i = 0; i < rows.length; i++) {
1222
		ae.SetAddressAccExt(i, rows[i].getElementsByTagName("input")[0].checked);
1223
		ae.SetAddressAccInt(i, rows[i].getElementsByTagName("input")[1].checked);
1224
	}
1225
1226
	ae.Address_Update(function(success) {
1227
		if (!success) console.log("Address/Update failed");
1228
		btn.disabled = false;
1229
	});
1230
};
1231
1232
document.getElementById("btn_reg").onclick = function() {
1233
	const btn = document.getElementById("btn_reg");
1234
	const txt = document.getElementById("txt_reg");
1235
	if (!txt.reportValidity()) return;
1236
	btn.disabled = true;
1237
1238
	ae.Account_Create(txt.value, function(success) {
1239
		if (success) {
1240
			addAccountToTable(ae.Admin_GetUserCount() - 1);
1241
			txt.value = "";
1242
		}
1243
1244
		btn.disabled = false;
1245
	});
1246
};
1247
1248
document.getElementById("chk_downme").onclick = function() {document.getElementById("btn_downme").disabled = !this.checked;};
1249
document.getElementById("chk_killme").onclick = function() {document.getElementById("btn_killme").disabled = !this.checked;};
1250
1251
document.getElementById("btn_notepad_saveupl").onclick = function() {
1252
	const np = document.getElementById("txt_notepad");
1253
	np.disabled = true;
1254
1255
	let fname = prompt("Save as...", "Untitled");
0 ignored issues
show
Debugging Code Best Practice introduced by
The prompt UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1256
	if (!fname.endsWith(".txt")) fname += ".txt";
1257
1258
	ae.Message_Upload(fname, np.value, function(success) {
1259
		if (success) {
1260
			np.value = "";
1261
			addUploads();
1262
			document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
1263
		}
1264
1265
		console.log("Failed to add text");
1266
		np.disabled = false;
1267
	});
1268
};
1269
1270
document.getElementById("btn_upload").onclick = function() {
1271
	const btn = this;
1272
	const fileSelector = document.createElement("input");
1273
	fileSelector.type = "file";
1274
	fileSelector.click();
1275
1276
	fileSelector.onchange = function() {
1277
		btn.disabled = true;
1278
1279
		const reader = new FileReader();
1 ignored issue
show
Bug introduced by
The variable FileReader seems to be never declared. If this is a global, consider adding a /** global: FileReader */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1280
		reader.onload = function() {
1281
			ae.Message_Upload(fileSelector.files[0].name, new Uint8Array(reader.result), function(success) {
1282
				if (success) {
1283
					addUploads();
1284
					document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
1285
				} else {
1286
					console.log("Failed upload");
1287
				}
1288
1289
				btn.disabled = false;
1290
			});
1291
		};
1292
1293
		reader.readAsArrayBuffer(fileSelector.files[0]);
1294
	};
1295
};
1296
1297
document.getElementById("btn_pg").onclick = function() {
1298
	localStorage.greeting = document.getElementById("txt_pg").value;
1 ignored issue
show
Bug introduced by
The variable localStorage seems to be never declared. If this is a global, consider adding a /** global: localStorage */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1299
};
1300
1301
document.getElementById("txt_skey").onkeyup = function(event) {
1302
	if (event.key === "Enter") {
1303
		event.preventDefault();
1304
		document.getElementById("btn_enter").click();
1305
	}
1306
};
1307
1308
document.getElementById("btn_enter").onclick = function() {
1309
	const txtSkey = document.getElementById("txt_skey");
1310
	if (!txtSkey.reportValidity()) return;
1311
1312
	const btn = this;
1313
	btn.disabled = true;
1314
	document.getElementById("txt_skey").style.background = "#233";
1315
1316
	ae.SetKeys(txtSkey.value, function(successSetKeys) {
1317
		if (successSetKeys) {
1318
			ae.Message_Browse(false, true, function(successBrowse) {
1319
				if (successBrowse) {
1320
					txtSkey.value = "";
1321
					document.getElementById("div_begin").hidden = true;
1322
					document.getElementById("div_main").style.display = "grid";
1323
					reloadAccount();
1324
1325
					if (ae.IsUserAdmin()) {
1326
						ae.Account_Browse(function(successAcc) {
1327
							if (successAcc) {for (let i = 0; i < ae.Admin_GetUserCount(); i++) {addAccountToTable(i);}}
1328
							else console.log("Failed to Account_Browse");
1329
						});
1330
					}
1331
				} else {
1332
					console.log("Failed to enter");
1333
					btn.disabled = false;
1334
					document.getElementById("txt_skey").style.background = "#466";
1335
					txtSkey.focus();
1336
				}
1337
			});
1338
		} else {
1339
			console.log("Invalid format for key");
1340
			btn.disabled = false;
1341
			document.getElementById("txt_skey").style.background = "#466";
1342
			txtSkey.focus();
1343
		}
1344
	});
1345
};
1346
1347
});
1348